{
 "cells": [
  {
   "cell_type": "raw",
   "metadata": {
    "vscode": {
     "languageId": "raw"
    }
   },
   "source": [
    "---\n",
    "title: Structs\n",
    "sidebar_position: 4\n",
    "description: Introduction to Mojo structures (structs).\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A Mojo struct is a data structure that allows you to encapsulate fields and\n",
    "methods that operate on an abstraction, such as a data type or an object.\n",
    "**Fields** are variables that hold data relevant to the struct, and **methods**\n",
    "are functions inside a struct that generally act upon the field data.\n",
    "\n",
    "For example, if you're building a graphics program, you can use a struct to\n",
    "define an `Image` that has fields to store information about each image\n",
    "(such as the pixels) and methods that perform actions on it (such as rotate\n",
    "it).\n",
    "\n",
    "For the most part, Mojo's struct format is designed to provide a static,\n",
    "memory-safe data structure for high-level data types used in programs. For\n",
    "example, all the data types in Mojo's standard library (such as `Int`,\n",
    "`Bool`, `String`, and `Tuple`) are defined as structs.\n",
    "\n",
    "If you understand how [functions](/mojo/manual/functions.html) and\n",
    "[variables](/mojo/manual/variables.html) work in Mojo, you probably\n",
    "noticed that Mojo is designed to provide dynamic programming features in a\n",
    "`def` function while enforcing stronger code safety in `fn` functions. When it\n",
    "comes to structs, Mojo leans toward the safe side: You can still choose whether\n",
    "to use either `def` or `fn` declarations for methods, but all fields must be\n",
    "declared with `var`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Struct definition\n",
    "\n",
    "You can define a simple struct called `MyPair` with two fields like this:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "struct MyPair:\n",
    "    var first: Int\n",
    "    var second: Int"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "However, you can't instantiate this struct because it has no constructor\n",
    "method. So here it is with a constructor to initialize the two fields:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "struct MyPair:\n",
    "    var first: Int\n",
    "    var second: Int\n",
    "\n",
    "    fn __init__(inout self, first: Int, second: Int):\n",
    "        self.first = first\n",
    "        self.second = second"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Notice that the first argument in the `__init__()` method is `inout self`. For\n",
    "now, ignore `inout` (it's an [argument\n",
    "convention](/mojo/manual/values/ownership.html#argument-conventions) that\n",
    "declares `self` as a mutable reference); all you need to know right now is that\n",
    "`self` must be the first argument. It references the current struct instance\n",
    "(it allows code in the method to refer to \"itself\"). *When you call the\n",
    "constructor, you never pass a value for `self`—Mojo passes it in \n",
    "automatically.*\n",
    "\n",
    "The `__init__()` method is one of many [special methods](#special-methods)\n",
    "(also known as \"dunder methods\" because they have *d*ouble *under*scores) with\n",
    "pre-determined names.\n",
    "\n",
    ":::note\n",
    "\n",
    "You can't assign values when you declare fields. You must initialize\n",
    "all of the struct's fields in the constructor. (If you try to leave a field\n",
    "uninitialized, the code won't compile.)\n",
    "\n",
    ":::\n",
    "\n",
    "Once you have a constructor, you can create an instance of `MyPair` and set the\n",
    "fields:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2\n"
     ]
    }
   ],
   "source": [
    "var mine = MyPair(2,4)\n",
    "print(mine.first)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Methods\n",
    "\n",
    "In addition to special methods like `__init__()`, you can add any other method\n",
    "you want to your struct. For example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "struct MyPair:\n",
    "    var first: Int\n",
    "    var second: Int\n",
    "\n",
    "    fn __init__(inout self, first: Int, second: Int):\n",
    "        self.first = first\n",
    "        self.second = second\n",
    "\n",
    "    fn get_sum(self) -> Int:\n",
    "        return self.first + self.second"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "14\n"
     ]
    }
   ],
   "source": [
    "var mine = MyPair(6, 8)\n",
    "print(mine.get_sum())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Notice that `get_sum()` also uses the `self` argument, because this is\n",
    "the only way you can access the struct's fields in a method. The name `self` is\n",
    "just a convention, and you can use any name you want to refer to the struct \n",
    "instance that is always passed as the first argument.\n",
    "\n",
    "Methods that take the implicit `self` argument are called _instance methods_ \n",
    "because they act on an instance of the struct. \n",
    "\n",
    ":::note\n",
    "\n",
    "The `self` argument in a struct method is the only argument in an\n",
    "`fn` function that does not require a type. You can include it if you want, but\n",
    "you can elide it because Mojo already knows its type (`MyPair` in this case).\n",
    "\n",
    ":::"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Static methods\n",
    "\n",
    "A struct can also have _static methods_. A static method can be called without \n",
    "creating an instance of the struct. Unlike instance methods, a static method\n",
    "doesn't receive the implicit `self` argument, so it can't access any fields on\n",
    "the struct.\n",
    "\n",
    "To declare a static method, use the `@staticmethod` decorator and don't include\n",
    "a `self` argument:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "struct Logger:\n",
    "\n",
    "    fn __init__(inout self):\n",
    "        pass\n",
    "\n",
    "    @staticmethod\n",
    "    fn log_info(message: String):\n",
    "        print(\"Info: \", message)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can invoke a static method by calling it on the type (in this case,\n",
    "`Logger`). You can also call it on an instance of the type. Both forms are\n",
    "shown below:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Info:  Static method called.\n",
      "Info:  Static method called from instance.\n"
     ]
    }
   ],
   "source": [
    "Logger.log_info(\"Static method called.\")\n",
    "var l = Logger()\n",
    "l.log_info(\"Static method called from instance.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Structs compared to classes\n",
    "\n",
    "If you're familiar with other object-oriented languages, then structs might\n",
    "sound a lot like classes, and there are some similarities, but also some\n",
    "important differences. Eventually, Mojo will also support classes to match the\n",
    "behavior of Python classes.\n",
    "\n",
    "So, let's compare Mojo structs to Python classes. They both support methods,\n",
    "fields, operator overloading, decorators for metaprogramming, and more, but\n",
    "their key differences are as follows:\n",
    "\n",
    "- Python classes are dynamic: they allow for dynamic dispatch, monkey-patching\n",
    "(or “swizzling”), and dynamically binding instance fields at runtime.\n",
    "\n",
    "- Mojo structs are static: they are bound at compile-time (you cannot add\n",
    "methods at runtime). Structs allow you to trade flexibility for performance\n",
    "while being safe and easy to use.\n",
    "\n",
    "- Mojo structs do not support inheritance (\"sub-classing\"), but a struct can\n",
    "  implement [traits](/mojo/manual/traits.html).\n",
    "\n",
    "- Python classes support class attributes—values that are shared by all\n",
    "  instances of the class, equivalent to class variables or static data members\n",
    "  in other languages.\n",
    "  \n",
    "- Mojo structs don't support static data members.\n",
    "\n",
    "Syntactically, the biggest difference compared to a Python class is that all\n",
    "fields in a struct must be explicitly declared with `var`.\n",
    "\n",
    "In Mojo, the structure and contents of a struct are set at compile time and\n",
    "can’t be changed while the program is running. Unlike in Python, where you can\n",
    "add, remove, or change attributes of an object on the fly, Mojo doesn’t allow\n",
    "that for structs.\n",
    "\n",
    "However, the static nature of structs helps Mojo run your code faster. The\n",
    "program knows exactly where to find the struct’s information and how to use it\n",
    "without any extra steps or delays at runtime.\n",
    "\n",
    "Mojo’s structs also work really well with features you might already know from\n",
    "Python, like operator overloading (which lets you change how math symbols like\n",
    "`+` and `-` work with your own data, using [special\n",
    "methods](#special-methods)).\n",
    "\n",
    "As mentioned above, all Mojo's standard types\n",
    "(`Int`, `String`, etc.) are made using structs, rather than being hardwired\n",
    "into the language itself. This gives you more flexibility and control when\n",
    "writing your code, and it means you can define your own types with all the same\n",
    "capabilities (there's no special treatment for the standard library types)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Special methods\n",
    "\n",
    "Special methods (or \"dunder methods\") such as `__init__()` are pre-determined\n",
    "method names that you can define in a struct to perform a special task.\n",
    "\n",
    "Although it's possible to call special methods with their method names, the\n",
    "point is that you never should, because Mojo automatically invokes them in\n",
    "circumstances where they're needed (which is why they're also called \"magic\n",
    "methods\"). For example, Mojo calls the `__init__()` method when you create\n",
    "an instance of the struct; and when Mojo destroys the instance, it calls the\n",
    "`__del__()` method (if it exists).\n",
    "\n",
    "Even operator behaviors that appear built-in (`+`, `<`, `==`, `|`, and so on)\n",
    "are implemented as special methods that Mojo implicitly calls upon to perform\n",
    "operations or comparisons on the type that the operator is applied to.\n",
    "\n",
    "Mojo supports a long list of special methods; far too many to discuss here, but\n",
    "they generally match all of [Python's special\n",
    "methods](https://docs.python.org/3/reference/datamodel.html#special-method-names)\n",
    "and they usually accomplish one of two types of tasks:\n",
    "\n",
    "- Operator overloading: A lot of special methods are designed to overload\n",
    "  operators such as `<` (less-than), `+` (add), and `|` (or) so they work\n",
    "  appropriately with each type. For example, look at the methods listed for Mojo's\n",
    "  [`Int` type](/mojo/stdlib/builtin/int/Int). One such method is `__lt__()`, which\n",
    "  Mojo calls to perform a less-than comparison between two integers (for example,\n",
    "  `num1 < num2`).\n",
    "\n",
    "- Lifecycle event handling: These special methods deal with the lifecycle and\n",
    "  value ownership of an instance. For example, `__init__()` and `__del__()`\n",
    "  demarcate the beginning and end of an instance lifetime, and other special\n",
    "  methods define the behavior for other lifecycle events such as how to copy or\n",
    "  move a value.\n",
    "\n",
    "You can learn all about the lifecycle special methods in the [Value\n",
    "lifecycle](/mojo/manual/lifecycle/) section. However, most structs are simple\n",
    "aggregations of other types, so unless your type requires custom behaviors when\n",
    "an instance is created, copied, moved, or destroyed, you can synthesize the\n",
    "essential lifecycle methods you need (and save yourself some time) by adding\n",
    "the `@value` decorator."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### `@value` decorator\n",
    "\n",
    "When you add the [`@value` decorator](/mojo/manual/decorators/value.html) to a\n",
    "struct, Mojo will synthesize the essential lifecycle methods so your object\n",
    "provides full value semantics. Specifically, it generates the `__init__()`,\n",
    "`__copyinit__()`, and `__moveinit__()` methods, which allow you to construct,\n",
    "copy, and move your struct type in a manner that's value semantic and\n",
    "compatible with Mojo's ownership model.\n",
    "\n",
    "For example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "@value\n",
    "struct MyPet:\n",
    "    var name: String\n",
    "    var age: Int"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Mojo will notice that you don't have a member-wise initializer, a move\n",
    "constructor, or a copy constructor, and it will synthesize these for you as if\n",
    "you had written:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "struct MyPet:\n",
    "    var name: String\n",
    "    var age: Int\n",
    "\n",
    "    fn __init__(inout self, owned name: String, age: Int):\n",
    "        self.name = name^\n",
    "        self.age = age\n",
    "\n",
    "    fn __copyinit__(inout self, existing: Self):\n",
    "        self.name = existing.name\n",
    "        self.age = existing.age\n",
    "\n",
    "    fn __moveinit__(inout self, owned existing: Self):\n",
    "        self.name = existing.name^\n",
    "        self.age = existing.age"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Without the copy and move constructors, the following code would not work\n",
    "because Mojo would not know how to copy an instance of `MyPet`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Charlie\n"
     ]
    }
   ],
   "source": [
    "var dog = MyPet(\"Charlie\", 5)\n",
    "var poodle = dog\n",
    "print(poodle.name)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "When you add the `@value` decorator, Mojo synthesizes each special method above\n",
    "only if it doesn't exist already. That is, you can still implement a custom\n",
    "version of each method.\n",
    "\n",
    "In addition to the `inout` argument convention you already saw with\n",
    "`__init__()`, this code also introduces `owned`, which is another argument\n",
    "convention that ensures the argument has unique ownership of the value.\n",
    "For more detail, see the section about [value\n",
    "ownership](/mojo/manual/values/ownership.html).\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Mojo",
   "language": "mojo",
   "name": "mojo-jupyter-kernel"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "mojo"
   },
   "file_extension": ".mojo",
   "mimetype": "text/x-mojo",
   "name": "mojo"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
